<?php


namespace fast;


class Package
{
    protected $list = [];
    protected $aloneRules = [];
    protected $mixRules = [];
    protected $packageList = [];
    public function __construct($list,$rules)
    {
        // 重构list,把同一规则的商品放在一起
        foreach ($list as $item){
            $this->list[$item['goods_sku_rule_id']]['rule_id'] = $item['goods_sku_rule_id'];
            $this->list[$item['goods_sku_rule_id']]['number']  = ($this->list[$item['goods_sku_rule_id']]['number'] ?? 0) + $item['number'];
            $this->list[$item['goods_sku_rule_id']]['weight']  = ($this->list[$item['goods_sku_rule_id']]['weight'] ?? 0) + bcmul($item['weight'] , $item['number'],2);
            $this->list[$item['goods_sku_rule_id']]['goods'][] = $item;
        }


        // 将单品规则和混装规则区分
        foreach ($rules as $rule){
            $content = [];
            $rule['content'] = json_decode($rule['content'],true);
            if($rule['content']){
                foreach ($rule['content'] as $r){
                    $ids = explode(',',$r['rule_ids']);
                    foreach ($ids as $id){
                        $content[$id] = $r['number'];
                    }
                }
                $rule['content'] = $content;
            }

            if($rule['type'] == 'alone'){
                $this->aloneRules[$rule['id']] = $rule;
            }else{
                $this->mixRules[$rule['id']] = $rule;
            }
        }

    }

    // 开始分箱
    public function buildPackage(){
        // 剩余单品混装
        $this->buildMix();
        // 首先分配单品
        $this->buildAlone();
        // 看分配后的单品能不能塞入其他产品
        $this->checkAlone();



        return $this->packageList;
    }


    // 单品分箱
    protected function buildAlone($trueBox = 0){
        $package = [];
        foreach ($this->list as $list){
            if($list['number'] > 0){
                if(isset($this->aloneRules[$list['rule_id']])){
                    $rule = $this->aloneRules[$list['rule_id']];
                    $rule['item_number'] = $rule['item_number'] == -1 ? 99 : $rule['item_number'];
                    $numberBoxNum = $rule['total_number'] > 0 ? floor($list['number'] / $rule['total_number']) : ($rule['total_number'] == -1 ? 99 : 0 );
                    $weightBoxNum = $rule['weight'] > 0 ? floor($list['weight'] / $rule['weight']) : ($rule['weight'] == -1 ? 99 : 0 );
                    $boxNum = $weightBoxNum > $numberBoxNum ? $weightBoxNum : $numberBoxNum;
                    //若传入箱数量也就是混装过剩下的单品直接入箱
                    if($trueBox > 0){
                        $boxNum = $trueBox;
                    }
                    if($boxNum > 0){
                        for ($i = 1;$i <= $boxNum;$i++){
                            $package[$rule['id']][$i]['rule_id'] = $rule['id'];
                            $package[$rule['id']][$i]['number'] = $package[$rule['id']][$i]['number'] ?? 0;
                            $package[$rule['id']][$i]['weight'] = $package[$rule['id']][$i]['weight'] ?? 0;
                            // 若剩余件数和剩余重量还未满则进入装货
                            if($package[$rule['id']][$i]['number'] < $rule['total_number'] && $package[$rule['id']][$i]['weight'] < $rule['weight']){
                                $surplusNumber = $rule['total_number'] - $package[$rule['id']][$i]['number']; // 该箱最大还可装数量
                                $surplusWeight = $rule['weight'] - $package[$rule['id']][$i]['weight'];  // 该箱最大还可装重量
                                foreach ($this->list[$rule['id']]['goods'] as $key => $goods){
                                    $package[$rule['id']][$i]['goods'][$goods['goods_sku_id']]['order_goods_number'] = $package[$rule['id']][$i]['goods'][$goods['goods_sku_id']]['order_goods_number'] ?? 0;
                                    if($rule['item_number'] > $package[$rule['id']][$i]['goods'][$goods['goods_sku_id']]['order_goods_number']){
                                        $aloneSurplusNumber = $rule['item_number'] - $package[$rule['id']][$i]['goods'][$goods['goods_sku_id']]['order_goods_number']; // 该单品在这箱里还可装几个
                                        for ($g = 0;$g < $goods['number'];$g++){
                                            if($aloneSurplusNumber > 0 && $surplusNumber > 0 && $surplusWeight > $goods['weight']){
                                                $package[$rule['id']][$i]['number']++;
                                                $package[$rule['id']][$i]['weight'] += $goods['weight'];
                                                $package[$rule['id']][$i]['goods'][$goods['goods_sku_id']]['sku_id'] = $goods['goods_sku_id'];
                                                $package[$rule['id']][$i]['goods'][$goods['goods_sku_id']]['order_goods_number']++;
                                                $aloneSurplusNumber --;
                                                $surplusNumber --;
                                                $surplusWeight -= $goods['weight'];
                                                $this->list[$rule['id']]['goods'][$key]['number']--;
                                                $this->list[$rule['id']]['number']--;
                                            }
                                        }
                                    }
                                    if(!$package[$rule['id']][$i]['goods'][$goods['goods_sku_id']]['order_goods_number']){
                                        unset($package[$rule['id']][$i]['goods'][$goods['goods_sku_id']]);
                                    }
                                }
                            }

                            if($package[$rule['id']][$i]['number'] == 0){
                                unset($package[$rule['id']][$i]);
                            }
                        }
                    }
                }
            }
        }

        $this->addPackage($package);
    }


    //混装分箱
    protected function buildMix(){
        $package = [];
        $list_rule_ids = [];
        foreach ($this->list as $list ){
            if($list['number'] > 0){
                $list_rule_ids[] = $list['rule_id'];
            }
        }
        if(count($list_rule_ids) > 1){
            // 先循环出交集最多的规则.
            $match_rule_id = 0;
            $match_number = 0;
            $content = [];
            $rule_total_number = 0;
            foreach ($this->mixRules as $r){
                $row_number = 0;
                $rule_ids = array_keys($r['content']);
                foreach ($list_rule_ids as $id){
                    if(in_array($id,$rule_ids)){
                        $row_number ++;
                    }
                }

                if($row_number >= $match_number && $r['total_number'] >= $rule_total_number){
                    $match_rule_id = $r['id'];
                    $match_number = $row_number;
                    $content = $r['content'];
                    $rule_total_number = $r['total_number'];
                }
            }

            if($match_number <= 1){
                return $this->BuildAlone(99);
            }
            $content_rule_ids = array_keys($content);
            $rule = $this->mixRules[$match_rule_id];
            $surplusNumber = $rule['total_number'];
            $surplusWeight = $rule['weight'];
            $package['rule_id'] = $match_rule_id;
            $package['number'] = 0;
            $package['weight'] = 0;
            $package['goods'] = [];
            foreach ($this->list as $key => $list){
                if(in_array($list['rule_id'],$content_rule_ids)){
                    foreach ($list['goods'] as $good_key => $goods){
                        $aloneSurplusNumber = $content[$list['rule_id']] - ($package['goods'][$goods['goods_sku_id']]['order_goods_number'] ?? 0); // 该单品在这箱里还可装几个
                        for ($g = 0;$g < $goods['number'];$g++){
                            if($aloneSurplusNumber > 0 && $surplusNumber > 0 && $surplusWeight > $goods['weight']){
                                $package['number']++;
                                $package['weight'] += $goods['weight'];
                                $package['goods'][$goods['goods_sku_id']]['sku_id'] = $goods['goods_sku_id'];
                                $package['goods'][$goods['goods_sku_id']]['order_goods_number'] = isset($package['goods'][$goods['goods_sku_id']]['order_goods_number']) ? ($package['goods'][$goods['goods_sku_id']]['order_goods_number'] + 1) : 1;
                                $aloneSurplusNumber --;
                                $surplusNumber --;
                                $surplusWeight -= $goods['weight'];
                                $this->list[$list['rule_id']]['goods'][$good_key]['number']--;
                                $this->list[$list['rule_id']]['number']--;
                            }
                        }
                    }
                }
            }
            $this->addPackage([[$package]]);
            return $this->buildMix();
        }else{
            return $this->BuildAlone(99);
        }
    }

    // 检测单品是否可继续塞东西
    protected function checkAlone(){
        foreach ($this->packageList as $key => $package){
            foreach ($package as $k => $p){
                foreach ($this->mixRules as $rule){
                    $rule_ids = explode(',',$rule['rule_ids']);
                    $content = $rule['content'];
                    if(in_array($p['rule_id'],$rule_ids) && $p['number'] < $rule['total_number'] && $p['weight'] < $rule['weight'] && $p['number'] <= $content[$p['rule_id']]){
                        $surplusNumber = $rule['total_number'] - $p['number'];
                        $surplusWeight = $rule['weight'] - $p['weight'];
                        foreach ($this->list as $goods_rule_id => $list){
                            if(in_array($goods_rule_id,$rule_ids) && $list['rule_id'] != $p['rule_id']){
                                foreach ($list['goods'] as $goods_key => $goods){
                                    if($goods['number'] > 0){
                                        $this->packageList[$key][$k]['rule_id'] = $rule['id'];
                                        $this->packageList[$key][$k]['goods'][$goods['goods_sku_id']]['sku_id'] = $goods['goods_sku_id'];
                                        $this->packageList[$key][$k]['goods'][$goods['goods_sku_id']]['order_goods_number'] = $this->packageList[$key][$k]['goods'][$goods['goods_sku_id']]['order_goods_number'] ?? 0;
                                        $aloneSurplusNumber = $content[$list['rule_id']] - $this->packageList[$key][$k]['goods'][$goods['goods_sku_id']]['order_goods_number']; // 该单品在这箱里还可装几个
                                        for ($g = 0;$g < $goods['number'];$g++){
                                            if($aloneSurplusNumber > 0 && $surplusNumber > 0 && $surplusWeight > $goods['weight']){
                                                $this->packageList[$key][$k]['goods'][$goods['goods_sku_id']]['order_goods_number']++;
                                                $this->packageList[$key][$k]['number']++;
                                                $this->packageList[$key][$k]['weight'] += $goods['weight'];
                                                $aloneSurplusNumber --;
                                                $surplusNumber --;
                                                $surplusWeight -= $goods['weight'];
                                                $this->list[$goods_rule_id]['goods'][$goods_key]['number']--;
                                                $this->list[$goods_rule_id]['number']--;
                                            }
                                        }
                                    }
                                }
                            }

                        }
                    }
                }
            }
        }
    }

    // 装箱
    protected function addPackage($package){
        if(!empty($package)){
            $this->packageList = array_merge($this->packageList,$package);
        }
    }

}